Uber Eats 支持现金支付
本文是 Uber 的客户端工程师团队讲述了如何开发最新版本司机端系列文章中的第四篇,该系列代号 Carbon ,是我们共享出行业务的核心。包括其它功能在内,Uber 司机端使得超过 300 万名司机可以查看费用、里程以及收益情况。2017 年我们结合司机的反馈开始对司机端进行重新设计,并在 2018 年 9 月份启动了该项目。
Uber 作为全球性公司,努力使其服务保证可用。所以要利用技术做到功能本地化。其中关键的一项工作是使用户可以选择最有效的付款方式,无论是信用卡,借记卡,或者是当地特殊的支付方式,例如现金支付。
对于 Uber 的大部分市场来说,其出行业务和外卖业务所使用的普遍支付方式并不是信用卡和借记卡。直到 2016 年,这些线上支付方式是主要支持的类型,这使得那些只用现金支付的用户很难去使用我们的服务。首次支持现金支付是在孟买,这里的乘客只有少部分有信用卡。所以他们很欢迎使用现金支付,接着我们在印度,拉丁美洲,非洲也支持了这种方式。
然而,直到 2017 年 9 月,外卖服务才支持现金支付,首次支持的城市也是孟买。迟到 2 年的原因是: 外卖三方市场的复杂性,它包括餐厅,配送员和食客。
克服这项挑战,即要改变操作流程又要支持新的技术。尤其我们新的司机端( Carbon )支持扩展现金支付的能力。通过这些创新服务,我们能够给全球更多的用户提供外卖服务。
现金收款的挑战
在出行业务支持现金支付的城市,司机留下现金,然后从线上支付的订单中去支付 Uber 的费用。这种情况下,智能派单系统保证司机接到足够的线上支付订单,以此来支付之前属于 Uber 的现金单费用。司机非常乐意在行程结束时能够及时收取现金,同时这项功能对那些没有信用卡的用户也是非常重要的。
对于拥有三方市场的外卖业务来说,大部分属于餐厅的现金需要配送员去收取。并且,对于信用卡,借记卡使用率不高的地区,派发足够多线上支付的订单去抵消未收付的现金是不太现实的。比起让配送员把现金送回餐厅,我们需要一个可持续的方法在食客和餐厅之间进行现金转移。
首先我们尝试了第三方的现金收款服务,例如有合作关系的便利店,传统的银行存款,转账。这种方法的问题在于:支持 Uber 外卖的城市并不都支持这些服务,并且限制了现金支付的地方,需要配送员停下来去完成那些不属于配送过程中的任务。
理想中的现金收款方法需要适用于现在和将来所有支持外卖服务的地区,并且方便于配送员操作。更进一步,当现金支付的地区不具备可靠的网络环境,现金交换操作能够完全离线完成。
我们新的方法
产品方案很新颖:利用所有餐厅作为一个现金流动的分布式网络。配送员带着之前订单的现金去往有合作关系的餐厅,然后用现金去支付订单,这与食客的支付方式无关。为了避免取餐过程中不必要的冲突,支付金额与订单金额相等,因为收到不等的金额会给餐厅的出纳造成混乱。餐厅还是能保持所有现金收入,并且乐于看到及时付款。 Uber 将会从后续的线上订单中扣除配送和预约。
这个机制运行的不错,它在当前和未来的外卖市场都能进行扩展,并且操作集成到了每次配送中,使现金支付成为配送过程中的常规组成部分。我们下一个挑战是:确保餐厅欠款的收集能够离线完成.幸运的是,新司机端中的离线功能能够覆盖一些 Case,例如司机在网络情况差的地方结束订单。这个功能与我们现金支付的需求很吻合。
利用乐观模式
在 Uber 运营的许多新兴市场,可靠的网络环境是不能保障的。之前的司机应用在整个行程中需要可靠的网络环境,这给我们的司机和配送员带来了令人沮丧的体验。例如,司机必须将乘客带到一个网络环境良好的地方才能结束订单。对于配送员来说,情况可能更糟,地下或建筑物内的交付和配送受网络环境影响更大。
新司机端的众多新功能中有一个是乐观模式(Optimistic Mode),它允许功能在无网情况下使用。当开启的时候,无论网络请求是否成功,应用的状态会立马更新并保持响应。失败的请求会被记录,缓存,并在网络恢复连接后进行重试。不管实际网络延时情况,应用能快速响应,用户能够正常操作。使用乐观模式,行程可以在弱网或无网情况下开始和结束。对于外卖服务,配送员可以在无网情况下完成整个餐厅现金收付流程。
餐厅欠款收集功能
如果希望餐厅能无缝从配送员那收集欠款,需要新版的 Android/iOS 司机端和餐厅端(使用 React Native 编写 ),以及新版的后端服务。我们构建了一个新的微服务( microservice )去支持餐厅的现金流服务,它的客户端( clients )有以下几个职责:
- 决定餐厅现金支付的资格。
- 计算建议支付的现金总额。
- 使用状态机来维持现金支付流程中的状态。
- 在手机端和餐厅端中显示格式化后的数据。
如图 1 所示,现金流包含以下几个状态:
图 1: 映射现实世界中配送员如何在餐厅结算现金欠款机制的现金流状态机模型。
在调度中时,配送员会默认选择完成现金支付的操作,之后的主动操作是需要网络连接时完成。如图 2,在配送开始时,会认为配送员是处于网络状态良好的环境中,否则,他们不会收到派送信息。之后我们会把流程结束的完整信息发送过去,这样后续操作不需要网络一直连接,并且会提醒餐厅可能是现金支付,如图 3 所示。配送员可能会退出现金支付页面并继续之后的派送流程,这时乐观模式( Optimistic Mode )会把失败请求存储到磁盘上。网络恢复连接后,会通知后端有临时跳过现金支付的决定。
图 2:配送应用上显示需要支付的金额和暂时跳过的选项,
图 3:取餐时餐厅收到可选现金支付的信息
服务支持配送员设置他们能支付的金额,如果配送员手上没有足够支付的金钱或者希望之后派送时再支付,这个功能会非常有用。然而,我们没有开启此功能,更多考虑的是餐厅会收到现金总额与订单总额不符的体验。在当前实践中,如果配送员选择完成现金支付,之后会进入支付状态交换,这时现金总额会自动设置为订单总额。
离线情况下我们如何进行现金支付交换呢?需要餐厅和配送员都能承认现金支付是令人安心的,可以预防潜在的欺诈。在双方确认后,不能依赖网络请求来提供及时通信,因此我们利用四位数验证码。
调度过程中,我们同时给司机端和餐厅端提供完成流程所需要的所有信息。如图 4,餐厅得到了一个随机生成的验证码,在现金交换时配送员会被提示去请求它。
图 4:在调度时,餐厅得到一个四位验证码。
相反地,发给手机端的是此验证码SHA256加盐后的 Hash 值,然后在输入餐厅得到的验证码时,会和该验证码的加盐 hash 值进行比对。一旦成功,配送员可以继续完成现金交换流程,并开始下一次配送。hash 值相等性验证发生在线下。为了避免作弊,会限制频率和最大尝试次数。 此外,如果现金支付操作没有完成,验证码会在合理时间内到期。如果发现事务不一致,Uber 会进一步调查,可能会禁止平台内任何有不良行为的用户。
图 5: 配送员输入验证码进行hash和验证。
如上图 5 所示,一旦验证码输入成功,配送员和餐厅应用会同时显示一个预填充确认的页面。如果网络又出现错误,乐观模式( Optimistic Mode )会缓存失败请求到磁盘,并在网络恢复时重试。配送员支付行为被记录为可信,餐厅的余额根据之后的线上收益进行调整,至此现金支付结束。
伴随现金支付前进
虽然乐观模式( Optimistic Mode )设计的初衷是为了 Carbon 的核心出行流程,但是它为这套全新功能的实现提供了可能。Uber 的工程师和设计师团队在开发新功能时摆脱了网络环境的限制。由于现金交接需要多方的高度信任,所以仅依靠餐厅去核实现金交易是行不通的。同时,配送员网络连接状态可能阻塞行程的进行,从而停留在验证的流程中。乐观模式( Optimistic Mode )完美解决了这个问题,它允许现金交接操作在离线环境中进行,并稍后在网络连接恢复时通知后端事务。
认识到离线操作的价值后,其他的 Carbon 开发团队都是用了乐观模式( Optimistic Mode ),而且 Uber 的移动端网络组在框架中拓展了此功能。这些努力使得 Uber 应用摆脱了网络环境的依赖,成为能离线响应多方市场的应用。
Index of articles in Uber driver app series
- Why We Decided to Rewrite Uber’s Driver App
- Architecting Uber’s New Driver App in RIBs
- How Uber’s New Driver App Overcomes Network Lag
- Uber Eats 支持现金支付
- How to Ship an App Rewrite Without Risking Your Entire Business
- Building a Scalable and Reliable Map Interface for Drivers
- Engineering Uber Beacon: Matching Riders and Drivers in 24-bit RGB Colors